using System;
using System.Collections.Generic;
using System.Linq;
using MoonFramework.Template;

namespace MoonFramework.Scripts.Event
{
    /// <summary>
    ///     事件中心，观察者广播站，单例模式设计
    /// </summary>
    public class EventCenter : BaseManager<EventCenter>
    {
        /// <summary>
        ///     key - 事件类型
        ///     value - 事件
        /// </summary>
        private readonly Dictionary<string, IEventInfo> events = new();

        /// <summary>
        ///     注册
        /// </summary>
        public void Register<T1, T2, T3>(string name)
        {
            if (events.ContainsKey(name))
                return;
            events.Add(name, new BaseItem<T1, T2, T3>());
        }

        public void Register<T1, T2>(string name)
        {
            if (events.ContainsKey(name))
                return;
            events.Add(name, new BaseItem<T1, T2>());
        }

        public void Register<T>(string name)
        {
            if (events.ContainsKey(name))
                return;
            events.Add(name, new BaseItem<T>());
        }

        public void Register(string name)
        {
            if (events.ContainsKey(name))
                return;
            events.Add(name, new BaseItem());
        }

        /// <summary>
        ///     移除事件
        /// </summary>
        public void RemoveCommand<T1, T2, T3>(string name, Action<T1, T2, T3> action, bool isDelete = false)
        {
            if(!events.TryGetValue(name, out var eventInfo)) return;
            ((BaseItem<T1, T2, T3>)eventInfo).Actions -= action;
            if(isDelete && (BaseItem<T1, T2, T3>)eventInfo == null) Delete(name);
        }

        public void RemoveCommand<T1, T2>(string name, Action<T1, T2> action, bool isDelete = false)
        {
            if(!events.TryGetValue(name, out var eventInfo)) return;
            ((BaseItem<T1, T2>)eventInfo).Actions -= action;
            if(isDelete && (BaseItem<T1, T2>)eventInfo == null) Delete(name);
        }

        public void RemoveCommand<T>(string name, Action<T> action, bool isDelete = false)
        {
            if(!events.TryGetValue(name, out var eventInfo)) return;
            ((BaseItem<T>)events[name]).Actions -= action;
            if(isDelete && (BaseItem<T>)eventInfo == null) Delete(name);
        }

        public void RemoveCommand(string name, Action action, bool isDelete = false)
        {
            if(!events.TryGetValue(name, out var eventInfo)) return;
            ((BaseItem)events[name]).Actions -= action;
            if(isDelete && (BaseItem)eventInfo == null) Delete(name);
        }

        /// <summary>
        ///     订阅事件
        /// </summary>
        public void SendCommand<T1, T2, T3>(string name, Action<T1, T2, T3> act)
        {
            if (events.TryGetValue(name, out var eventInfo))
            {
                ((BaseItem<T1, T2, T3>)eventInfo).Actions += act;
            }
        }

        public void SendCommand<T1, T2>(string name, Action<T1, T2> act)
        {
            if (events.TryGetValue(name, out var eventInfo))
            {
                ((BaseItem<T1, T2>)eventInfo).Actions += act;
            }
        }

        public void SendCommand<T>(string name, Action<T> act)
        {
            if (events.TryGetValue(name, out var eventInfo))
            {
                ((BaseItem<T>)eventInfo).Actions += act;
            }
        }

        public void SendCommand(string name, Action act)
        {
            if (events.TryGetValue(name, out var eventInfo))
            {
                ((BaseItem)eventInfo).Actions += act;
            }
        }

        /// <summary>
        ///     触发事件
        /// </summary>
        public void Callback<T1, T2, T3>(string name, T1 info1, T2 info2, T3 info3)
        {
            if (events.TryGetValue(name, out var baseItem))
                ((BaseItem<T1, T2, T3>)baseItem).Actions?.Invoke(info1, info2, info3);
        }

        public void Callback<T1, T2>(string name, T1 info1, T2 info2)
        {
            if (events.TryGetValue(name, out var baseItem))
                ((BaseItem<T1, T2>)baseItem).Actions?.Invoke(info1, info2);
        }

        public void Callback<T>(string name, T info)
        {
            if (events.TryGetValue(name, out var baseItem)) 
                ((BaseItem<T>)baseItem).Actions?.Invoke(info);
        }

        public void Callback(string name)
        {
            if (events.TryGetValue(name, out var baseItem)) 
                ((BaseItem)baseItem).Actions?.Invoke();
        }

        /// <summary>
        ///     检查是否存在事件
        /// </summary>
        public bool HasEvent<T1, T2, T3>(string name, Action<T1, T2, T3> action)
        {
            return events.TryGetValue(name, out var info) && CreateAction<T1, T2, T3>(info).GetInvocationList().Contains(action);
        }

        public bool HasEvent<T1, T2>(string name, Action<T1, T2> action)
        {
            return events.TryGetValue(name, out var info) && CreateAction<T1, T2>(info).GetInvocationList().Contains(action);
        }

        public bool HasEvent<T>(string name, Action<T> action)
        {
            return events.TryGetValue(name, out var info) && CreateAction<T>(info).GetInvocationList().Contains(action);
        }

        public bool HasEvent(string name, Action action)
        {
            return events.TryGetValue(name, out var info) && CreateAction(info).GetInvocationList().Contains(action);
        }

        /// <summary>
        ///     创建 Action
        /// </summary>
        private Action<T1, T2, T3> CreateAction<T1, T2, T3>(IEventInfo info)
        {
            return ((BaseItem<T1, T2, T3>)info).Actions;
        }

        private Action<T1, T2> CreateAction<T1, T2>(IEventInfo info)
        {
            return ((BaseItem<T1, T2>)info).Actions;
        }

        private Action<T> CreateAction<T>(IEventInfo info)
        {
            return ((BaseItem<T>)info).Actions;
        }

        private Action CreateAction(IEventInfo info)
        {
            return ((BaseItem)info).Actions;
        }

        /// <summary>
        ///     删除指定事件
        /// </summary>
        public void Delete(string name)
        {
            if (!events.Remove(name, out var info))
                return;
        }

        /// <summary>
        ///     清空所有事件
        /// </summary>
        public void Clear()
        {
            events.Clear();
        }

        #region IEventInfo
        private interface IEventInfo
        {
        }

        private class BaseItem<T> : IEventInfo
        {
            public Action<T> Actions;
        }

        private class BaseItem<T1, T2> : IEventInfo
        {
            public Action<T1, T2> Actions;
        }

        private class BaseItem<T1, T2, T3> : IEventInfo
        {
            public Action<T1, T2, T3> Actions;
        }

        private class BaseItem : IEventInfo
        {
            public Action Actions;
        }
        #endregion
    }
}